use std::{
  borrow::Cow,
  fmt::Display,
  sync::{MutexGuard, PoisonError, RwLockReadGuard, RwLockWriteGuard},
};

/// web result
pub type Result<T, E = Error> = std::result::Result<T, E>;
/// Any Error
pub type AnyError = Box<dyn std::error::Error>;
/// Any Result
pub type AnyResult<T> = std::result::Result<T, AnyError>;

/// Http share error
#[derive(thiserror::Error, Debug, Clone)]
pub enum Error {
  /// Decode
  #[error("Decoding error: {0}")]
  Decode(String),
  /// RwLock read lock error
  #[error("RwLock read error: {0}")]
  RwLockReadError(String),
  /// RwLock write lock error
  #[error("RwLock write error: {0}")]
  RwLockWriteError(String),
  /// Mutex lock error
  #[error("Mutex error: {0}")]
  MutexError(String),
  /// MPSC Recv Error
  #[error("Mpsc Recv Error: {0}")]
  RecvError(#[from] std::sync::mpsc::RecvError),
  /// BadRequest `400 Bad Request`
  #[error("400 Bad Request")]
  BadRequest,
  /// Already exists
  #[error("Exists: {0}")]
  Exists(Cow<'static, str>),
  /// SerdeJson `400 Bad Request`
  // #[cfg(feature = "serde_json")]
  // #[error("400 SerdeJson error: {0}")]
  // SerdeJson(#[from] serde_json::Error),
  /// Result `400 Bad Request`
  #[error("Str: {0}")]
  Str(Cow<'static, str>),
  ///
  #[error("String: {0}")]
  String(String),
  /// Excel `400 Bad Request`
  #[cfg(feature = "regex")]
  #[error("regex error: {0}")]
  Regex(#[from] regex::Error),
  /// Return `401 Unauthorized`
  #[error("authentication required: {0}")]
  Unauthorized(&'static str),
  /// Return `403 Forbidden`
  #[error("user may not perform that action")]
  Forbidden,
  /// Return `404 Not Found`
  #[error("request path not found: {0}")]
  NotFound(Cow<'static, str>),
  /// Return `404 Not Found`
  #[error("Option<{0}>")]
  Option(Cow<'static, str>),
  /// Not supported
  #[error("Not supported: {0}")]
  Unsupport(Cow<'static, str>),
  ///
  #[error("TryFromSlice: {0}")]
  TryFromSlice(#[from] std::array::TryFromSliceError),
  // /// IO return `500 INTERNAL_SERVER_ERROR`
  // #[error("an error occurred with the std io: {0}")]
  // Io(#[from] std::io::Error),
  /// Env
  #[error("env var error : {0}")]
  Env(#[from] std::env::VarError),
  ///
  #[error("Empty")]
  Empty,
  // /// Std error return `500 INTERNAL_SERVER_ERROR`
  // #[error("an error occurred with the std Error: {0}")]
  // Std(#[from] AnyError),
  /// Parse int error return 400
  #[error("an error occurred with the parse Error: {0}")]
  ParseNumber(#[from] std::num::ParseIntError),
  /// Parse float error return 400
  #[error("an error occurred with the parse Error: {0}")]
  ParseFloatError(#[from] std::num::ParseFloatError),
  /// Return `502 Internal Server Error` on an `anyhow::Error`.
  #[error("Log: {0}")]
  Log(Cow<'static, str>),
  /// Nul
  #[error("CString: {0}")]
  Nul(#[from] std::ffi::NulError),
  /// Any
  #[error("{0}")]
  Any(String),
}

impl From<String> for Error {
  fn from(s: String) -> Self {
    Error::String(s)
  }
}
impl From<&'static str> for Error {
  fn from(s: &'static str) -> Self {
    Error::Str(Cow::Borrowed(s))
  }
}
impl<T: Send + Sync + 'static> From<PoisonError<RwLockReadGuard<'_, T>>> for Error {
  fn from(err: PoisonError<RwLockReadGuard<'_, T>>) -> Self {
    Error::RwLockReadError(err.to_string())
  }
}

impl<T: Send + Sync + 'static> From<PoisonError<MutexGuard<'_, T>>> for Error {
  fn from(err: PoisonError<MutexGuard<'_, T>>) -> Self {
    Error::MutexError(err.to_string())
  }
}

impl<T: Send + Sync + 'static> From<PoisonError<RwLockWriteGuard<'_, T>>> for Error {
  fn from(err: PoisonError<RwLockWriteGuard<'_, T>>) -> Self {
    Error::RwLockWriteError(err.to_string())
  }
}

/// Any Result
pub trait AnyRes<T, E> {
  /// change  any
  fn any(self) -> Result<T>;
}

impl<T, E: Display> AnyRes<T, E> for std::result::Result<T, E> {
  fn any(self) -> Result<T> {
    match self {
      Ok(v) => Result::Ok(v),
      Err(e) => Result::Err(Error::Any(e.to_string())),
    }
  }
}
